#include "MFunction_Type.h"
BEGIN_MARIONETTE

inline PBYTE DetourGenPush(PBYTE pbCode, UINT32 nValue)
{
	*pbCode++ = 0x68;
	*((UINT32*&)pbCode)++ = nValue;
	return pbCode;
}

inline PBYTE DetourGenPushad(PBYTE pbCode)
{
	*pbCode++ = 0x60;
	return pbCode;
}

inline PBYTE DetourGenPopad(PBYTE pbCode)
{
	*pbCode++ = 0x61;
	return pbCode;
}
inline PBYTE DetourGenCall(PBYTE pbCode, PBYTE pbJmpDst, PBYTE pbJmpSrc = 0)
{
	if (pbJmpSrc == 0) {
		pbJmpSrc = pbCode;
	}
	*pbCode++ = 0xE8;
	*((INT32*&)pbCode)++ = pbJmpDst - (pbJmpSrc + 5);
	return pbCode;
}

inline PBYTE DetourGenBreak(PBYTE pbCode)
{
	*pbCode++ = 0xcc;
	return pbCode;
}

inline PBYTE DetourGenRet(PBYTE pbCode)
{
	*pbCode++ = 0xc3;
	return pbCode;
}  
inline PBYTE DetourGenAddEspByte(PBYTE pbCode,BYTE value)
{
	*pbCode++ = 0x83;
	*pbCode++ = 0xc4;
	*pbCode++ = value;
	return pbCode;
}
//////////////////////////////////////////////////////////////////////////
MFunction_Type::MFunction_Type(void)
:m_ArgumentOpoerators(5)
{
	m_LastArgumentIndex = 0;
}


MFunction_Type::~MFunction_Type(void)
{
	ResetArgumentDefine();

}

Marionette::MValue MFunction_Type::Call(MValue* v, MArguments* pArgs )
{
	PBYTE pCode = (PBYTE)m_Code;
	typedef DWORD (*TargetFunc_type)();
	TargetFunc_type TargetFunc = (TargetFunc_type)pCode;

	//pCode = DetourGenPushad(pCode);
	pCode = GenTranslateArgument(pCode, pArgs);
	pCode = DetourGenCall(pCode,(PBYTE)v->Address());
	pCode = GenFlatStack(pCode);
	//pCode = DetourGenPopad(pCode);

	pCode = DetourGenRet(pCode);
	DWORD oldFlag;
	VirtualProtect((LPVOID)TargetFunc,1000,PAGE_EXECUTE_READWRITE,&oldFlag);
	TargetFunc();
	VirtualProtect((LPVOID)TargetFunc,1000,oldFlag,&oldFlag);
	return MValue(0x00,NULL);
}

void MFunction_Type::DefineArgument( int index,ASM::ArgumentOperator* asmOperator )
{
	m_ArgumentOpoerators[index] = asmOperator;
	if(m_LastArgumentIndex < index)
		m_LastArgumentIndex = index;
}

void MFunction_Type::ResetArgumentDefine()
{
	for(unsigned int i=0;i<m_ArgumentOpoerators.size();i++)
	{
		if(m_ArgumentOpoerators[i] != NULL)
			delete m_ArgumentOpoerators[i];
	}
	m_LastArgumentIndex = 0;
}

PBYTE MFunction_Type::GenTranslateArgument( PBYTE pCode, MArguments* pArgs )
{
	for(int i=m_LastArgumentIndex;i>=0;i--)
		pCode = (PBYTE)m_ArgumentOpoerators[i]->GanerateCode(pCode,(*pArgs)[i]);
	return pCode;
}

PBYTE MFunction_Type::GenFlatStack( PBYTE pCode )
{
	pCode = DetourGenAddEspByte(pCode,(m_LastArgumentIndex+1)*4);
	return pCode;
}

//////////////////////////////////////////////////////////////////////////

void* ASM::PUSH::GanerateCode( void* pCode ,DWORD value)
{
	return (void*)DetourGenPush((PBYTE)pCode,value);	
}


ASM::ArgumentOperator* ASM::NEW_PUSH()
{
	return new ASM::PUSH();
}

END_MARIONETTE